
#define _NAND_CLASS_C_

#include "nand_blk.h"
#include "nand_dev.h"

extern int debug_data;

extern uint32 gc_all(void *zone);
extern uint32 gc_one(void *zone);
extern uint32 prio_gc_one(void *zone, uint16 block, uint32 flag);
extern void print_nftl_zone(void *zone);
extern void print_free_list(void *zone);
extern void print_smart(void *zone);
extern void print_block_invalid_list(void *zone);
extern void print_logic_page_map(void *_zone, uint32 num);
extern uint32 nftl_set_zone_test(void *_zone, uint32 num);
extern int nand_dbg_phy_read(unsigned short nDieNum, unsigned short nBlkNum,
			     unsigned short nPage);
extern int nand_dbg_zone_phy_read(void *zone, uint16 block, uint16 page);
extern int nand_dbg_zone_erase(void *zone, uint16 block, uint16 erase_num);
extern int nand_dbg_zone_phy_write(void *zone, uint16 block, uint16 page);
extern int nand_dbg_phy_write(unsigned short nDieNum, unsigned short nBlkNum,
			      unsigned short nPage);
extern int nand_dbg_phy_erase(unsigned short nDieNum, unsigned short nBlkNum);
extern int nand_dbg_single_phy_erase(unsigned short nDieNum,
				     unsigned short nBlkNum);
extern int _dev_nand_read2(char *name, __u32 start_sector, __u32 len,
			   unsigned char *buf);

extern void nand_phy_test(void);
extern int nand_check_table(void *zone);

extern void udisk_test_start(struct _nftl_blk *nftl_blk);
extern void udisk_test_stop(void);

static ssize_t nand_test_store(struct kobject *kobject, struct attribute *attr,
			       const char *buf, size_t count);
static ssize_t nand_test_show(struct kobject *kobject, struct attribute *attr,
			      char *buf);
void obj_test_release(struct kobject *kobject);
void udisk_test_speed(struct _nftl_blk *nftl_blk);

int g_iShowVar = -1;

struct attribute prompt_attr = {
	.name = "nand_debug",
	.mode = S_IRUGO | S_IWUSR | S_IWGRP | S_IROTH
};

static struct attribute *def_attrs[] = {
	&prompt_attr,
	NULL
};

struct sysfs_ops obj_test_sysops = {
	.show = nand_test_show,
	.store = nand_test_store
};

struct kobj_type ktype = {
	.release = obj_test_release,
	.sysfs_ops = &obj_test_sysops,
	.default_attrs = def_attrs
};

/*****************************************************************************
*Name         :
*Description  :
*Parameter    :
*Return       :
*Note         :
*****************************************************************************/
void obj_test_release(struct kobject *kobject)
{
	nand_dbg_err("release");
}

/*****************************************************************************
*Name         :
*Description  :
*Parameter    :
*Return       :
*Note         :
*****************************************************************************/
static ssize_t nand_test_show(struct kobject *kobject, struct attribute *attr,
			      char *buf)
{
	ssize_t count = 0;
	struct nand_kobject *nand_kobj;

	nand_kobj = (struct nand_kobject *)kobject;

	print_nftl_zone(nand_kobj->nftl_blk->nftl_zone);

	count = sprintf(buf, "%i", g_iShowVar);

	return count;
}

/*****************************************************************************
*Name         :
*Description  :receive testcase num from echo command
*Parameter    :
*Return       :
*Note         :
*****************************************************************************/
static ssize_t nand_test_store(struct kobject *kobject, struct attribute *attr,
			       const char *buf, size_t count)
{
	int ret, i;
	int argnum = 0;
	char cmd[32] = { 0 };
	unsigned int param0 = 0;
	unsigned int param1 = 0;
	unsigned int param2 = 0;
	char param3[16] = { 0 };
	char *tempbuf;

	struct nand_kobject *nand_kobj;
	nand_kobj = (struct nand_kobject *)kobject;

	g_iShowVar = -1;

	argnum =
	    sscanf(buf, "%s %u %u %u %s", cmd, &param0, &param1, &param2,
		   param3);
	nand_dbg_err("argnum=%i, cmd=%s, param0=%u, param1=%u, param2=%u\n",
		     argnum, cmd, param0, param1, param2);

	if (-1 == argnum) {
		nand_dbg_err("cmd format err!");
		g_iShowVar = -3;
		goto NAND_TEST_STORE_EXIT;
	}

	if (strcmp(cmd, "help") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  2013-10-24 19:48 \n");
	} else if (strcmp(cmd, "flush") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  flush\n");
		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		ret =
		    nand_kobj->nftl_blk->flush_write_cache(nand_kobj->nftl_blk,
							   param0);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "gcall") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  gcall\n");
		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		ret = gc_all(nand_kobj->nftl_blk->nftl_zone);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "gcone") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  gcone\n");
		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		ret = gc_one(nand_kobj->nftl_blk->nftl_zone);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "priogc") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  priogc\n");
		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		ret =
		    prio_gc_one(nand_kobj->nftl_blk->nftl_zone, param0, param1);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "test") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  test\n");
		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		ret =
		    nftl_set_zone_test((void *)nand_kobj->nftl_blk->nftl_zone,
				       param0);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "showall") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  show all\n");
		print_free_list(nand_kobj->nftl_blk->nftl_zone);
		print_block_invalid_list(nand_kobj->nftl_blk->nftl_zone);

		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "showinfo") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  show info\n");
		print_nftl_zone(nand_kobj->nftl_blk->nftl_zone);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "blkdebug") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("  blk debug\n");
		debug_data = param0;
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "smart") == 0) {
		nand_dbg_err("nand debug cmd:\n");
		nand_dbg_err("smart info\n");
		print_smart(nand_kobj->nftl_blk->nftl_zone);
		goto NAND_TEST_STORE_EXIT;
	} else if (strcmp(cmd, "read1") == 0) {
		nand_dbg_err("nand read1 cmd:\n");
		nand_dbg_phy_read(param0, param1, param2);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "read2") == 0) {
		nand_dbg_err("nand read2 cmd:\n");
		nand_dbg_zone_phy_read(nand_kobj->nftl_blk->nftl_zone, param0,
				       param1);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "erase1") == 0) {
		nand_dbg_err("nand erase1 cmd:\n");
		nand_dbg_phy_erase(param0, param1);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "erase2") == 0) {
		nand_dbg_err("nand erase2 cmd:\n");
		nand_dbg_zone_erase(nand_kobj->nftl_blk->nftl_zone, param0,
				    param1);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "erase3") == 0) {
		nand_dbg_err("nand erase3 cmd:\n");
		nand_dbg_single_phy_erase(param0, param1);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "write1") == 0) {
		nand_dbg_err("nand read1 cmd:\n");
		nand_dbg_phy_write(param0, param1, param2);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "write2") == 0) {
		nand_dbg_err("nand read2 cmd:\n");
		nand_dbg_zone_phy_write(nand_kobj->nftl_blk->nftl_zone, param0,
					param1);
		goto NAND_TEST_STORE_EXIT;
	}
#if 0
	else if (strcmp(cmd, "phytest") == 0) {
		nand_dbg_err("nand read2 cmd:\n");
		nand_phy_test();
		goto NAND_TEST_STORE_EXIT;
	}
#endif
	else if (strcmp(cmd, "checktable") == 0) {
		nand_dbg_err("nand read2 cmd:\n");

		mutex_lock(nand_kobj->nftl_blk->blk_lock);
		nand_check_table(nand_kobj->nftl_blk->nftl_zone);
		mutex_unlock(nand_kobj->nftl_blk->blk_lock);

		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "testspeed") == 0) {
		nand_dbg_err("nand runtest cmd:\n");
		udisk_test_speed(nand_kobj->nftl_blk);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "teststart") == 0) {
		nand_dbg_err("nand runtest cmd:\n");
		udisk_test_start(nand_kobj->nftl_blk);
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "teststop") == 0) {
		nand_dbg_err("nand runtest cmd:\n");
		udisk_test_stop();
		goto NAND_TEST_STORE_EXIT;
	}

	else if (strcmp(cmd, "readdev") == 0) {
		nand_dbg_err("nand dev read\n");
		if (param1 > 16) {
			nand_dbg_err("max len is 16!\n");
			goto NAND_TEST_STORE_EXIT;
		}
		mutex_lock(nand_kobj->nftl_blk->blk_lock);

		tempbuf = kmalloc(8192, GFP_KERNEL);
		_dev_nand_read2(param3, param0, param1, tempbuf);
		for (i = 0; i < (param1 << 9); i += 4) {
			printk("%8x ", *((int *)&tempbuf[i]));
			if (((i + 4) % 64) == 0)
				printk("\n");

		}
		kfree(tempbuf);

		mutex_unlock(nand_kobj->nftl_blk->blk_lock);

		goto NAND_TEST_STORE_EXIT;
	} else {
		nand_dbg_err("err, nand debug undefined cmd: %s\n", cmd);
	}

NAND_TEST_STORE_EXIT:
	return count;
}

extern int _dev_nand_read2(char *name, unsigned int start_sector,
			   unsigned int len, unsigned char *buf);
extern int _dev_nand_write2(char *name, unsigned int start_sector,
			    unsigned int len, unsigned char *buf);

struct timeval tpstart2, tpend2;
long timeuse2;

void udisk_test_speed(struct _nftl_blk *nftl_blk)
{
	char *test_buf;

	unsigned int start_sector;
	unsigned int len;
	unsigned int i;
	unsigned int sec;
	int usec;

	test_buf = kmalloc(0x100000, GFP_KERNEL);

	do_gettimeofday(&tpstart2);

	start_sector = 0x32000;
	len = 0x800;
	for (i = 0; i < 500; i++) {
		mutex_lock(nftl_blk->blk_lock);
		_dev_nand_write2("UDISK", start_sector + i * len, len,
				 test_buf);
		mutex_unlock(nftl_blk->blk_lock);
	}

	do_gettimeofday(&tpend2);

	sec = tpend2.tv_sec - tpstart2.tv_sec;
	usec = tpend2.tv_usec - tpstart2.tv_usec;

	printk("write sec:%d  usec:%d\n", sec, usec);

	do_gettimeofday(&tpstart2);

	start_sector = 0x32000;
	len = 0x800;
	for (i = 0; i < 500; i++) {
		mutex_lock(nftl_blk->blk_lock);
		_dev_nand_read2("UDISK", start_sector + i * len, len, test_buf);
		mutex_unlock(nftl_blk->blk_lock);
	}

	do_gettimeofday(&tpend2);

	sec = tpend2.tv_sec - tpstart2.tv_sec;
	usec = tpend2.tv_usec - tpstart2.tv_usec;

	printk("read sec:%d  usec:%d\n", sec, usec);

	kfree(test_buf);
	return;
}
